#ifndef _WANGXUAN_INDEX_MANAGER_H_
#define _WANGXUAN_INDEX_MANAGER_H_

#include "file_manager.h"
#include "key_helper.h"
#include <vector>
#include <string>
#include <map>


using namespace std;

class IndexManager{
public:
	static IndexManager* instance(const char* path=NULL,const char* prefix=NULL,const char* keyConfig=NULL);
	~IndexManager();
private:
	IndexManager();
public:
	int insert(const void* key,uint64_t msgId);
	int del(const void* key,uint64_t msgId);
	int find(const void* key,char* condition,int direction,void* buf,int& c);

	
	int findEx(const void* key,int kc,unsigned int startTime,uint64_t msgId,void* buf,int& c);
	int findPerOne(const void* key,int kc,void* buf,int& c);
	int findNewCount(const void* key,int kc,int startTime,uint64_t msgId,int& c);
	int findMsgCount(const void* key, int& c, int kc=2);
	
	int findLR(const void* keyLeft,const void* keyRight,KeyHelper::DIRECTION direct,void* buf,int& c,int offset=8);


	int freePages();
	int remap();
	int setMaxMemory(uint64_t maxMemory);
	int routine();

	void dump();

	static int createFile(const char* path,const char* prefix,int seq);
	int loadFile(int seq,IndexFile** file);

public:
	int getTreeM();
	int getTreeKeyNum();
	int getBlockSize();
	void getRootPage(IndexFilePage **rootPage);
	void getFileHeader(FileHeader **fh);
	void getPageNode(IndexFilePage *idxFilePage,NODE **node);
	uint64_t getPageOffset(IndexFilePage *idxFilePage);
	int getNextFileSeq();
	void getAllDataPageMap(IndexFile *idxFile,map<int,Page*> &pagesMap);
private:	
	int allocPage(IndexFilePage** idxPage);
	int freePage(IndexFilePage* idxPage);
	int getPage(uint64_t offset,IndexFilePage** idxPage);	
	
	static int startFileExtentThread();

	//find the key pos in the leaf node
	int findPos(const IndexFilePage* root , const void* key,uint64_t& offset, int& idx,KeyHelper::DIRECTION direct=KeyHelper::LEFT);
	int sortMerge(const void* src1,int c1,const void* src2,int c2,void* dest,int& dc);
	int findCount(const void* keyLeft,const void* keyRight,int& c);
	
	int extent();
	//int getNextFileSeq();
private:
	static void* fileExtent(void*);
	int init(const char* path,const char* prefix,const char* keyConfig);
private:
	int btreeInsertNonFull(IndexFilePage* node,  const void* key,uint64_t msgId);
	int btreeSplitChild(IndexFilePage* parent,int pos,IndexFilePage* child);
	int btreeFindIndex(const IndexFilePage* node,const void* key,int* ret);
	IndexFilePage* btreeDel(IndexFilePage* root,const void* key,uint64_t msgId);

	void* getKey(const IndexFilePage* idxPage,int idx);
	uint64_t getData(const IndexFilePage* idxPage,int idx);
private:
	//volatile int nextFileSeq;
	bool initFlag;
	char path[MAX_PATH_LEN];
	char prefix[MAX_PREFIX_LEN];
	map<int,IndexFile*>  fMap;

	KeyHelper kh;
	int blockSize;    //btree node per key+child or key+data size
	int m;			// 2m-1=key
	int keyNum;		//btree per node's key count
	unsigned int maxPageCount; //we may keep pages in memory no more than this 
	
	IndexFileHeader* idxFileHeader;
	IndexFilePage* rootPage;
};


inline int IndexManager::getNextFileSeq(){
	if ( idxFileHeader!=NULL) return idxFileHeader->fh->nextFileSeq;
	else return 0; 
}

inline void* IndexManager::getKey(const IndexFilePage* idxPage,int idx){
	return idxPage->node->data + blockSize * idx;
}

inline uint64_t IndexManager::getData(const IndexFilePage* idxPage,int idx)
{
	return *((uint64_t*)(idxPage->node->data + blockSize * idx + kh.getKeyLen()));
}

inline int IndexManager::setMaxMemory(uint64_t maxMemory){
	maxPageCount = maxMemory / PER_PAGE_SIZE;

	return 0;
}

inline int IndexManager::getTreeM()
{
	return m;
}

inline int IndexManager::getTreeKeyNum()
{
	return keyNum;
}

inline int IndexManager::getBlockSize()
{
	return blockSize;
}

inline void IndexManager::getRootPage(IndexFilePage **root)
{
	*root= rootPage;
}

inline void IndexManager::getFileHeader(FileHeader **fh)
{
	*fh = idxFileHeader->fh;
}

inline void IndexManager::getPageNode(IndexFilePage *idxFilePage,NODE **node)
{
	*node = idxFilePage->node;
}

inline uint64_t IndexManager::getPageOffset(IndexFilePage *idxFilePage)
{
	return idxFilePage->offset;
}
inline void IndexManager::getAllDataPageMap(IndexFile *idxFile,map<int,Page*> &pagesMap)
{
	pagesMap = idxFile->pagesMap;
}

#endif

